package com.yang.moyu.meta.system.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.yang.moyu.meta.common.util.ApiResult;
import com.yang.moyu.meta.config.properties.JwtProperties;
import com.yang.moyu.meta.config.properties.ShiroProperties;
import com.yang.moyu.meta.framework.constant.CommonRedisKey;
import com.yang.moyu.meta.framework.shiro.jwt.JwtToken;
import com.yang.moyu.meta.framework.shiro.service.LoginRedisService;
import com.yang.moyu.meta.framework.shiro.util.JwtUtil;
import com.yang.moyu.meta.framework.shiro.util.SaltUtil;
import com.yang.moyu.meta.framework.shiro.vo.LoginSysUserVo;
import com.yang.moyu.meta.framework.util.JwtTokenUtil;
import com.yang.moyu.meta.system.domain.SysDepartment;
import com.yang.moyu.meta.system.domain.SysRole;
import com.yang.moyu.meta.system.domain.SysUser;
import com.yang.moyu.meta.system.params.LoginParam;
import com.yang.moyu.meta.system.params.ResetPwdParam;
import com.yang.moyu.meta.system.service.*;
import com.yang.moyu.meta.system.vo.LoginSysUserTokenVo;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.subject.Subject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.time.Duration;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;

/**
 * Create by 10296 on 2021/12/16
 *
 * @Description: 登录服务类
 */
@Service
public class LoginServiceImpl implements LoginService {

    private Logger logger = LoggerFactory.getLogger(this.getClass());

    //    @Autowired
//    private RedisTemplate redisTemplate;
    @Autowired
    private SysUserService sysUserService;
    @Autowired
    private SysDepartmentService departmentService;
    @Autowired
    private SysRoleService sysRoleService;
    @Autowired
    private SysRolePermissionService sysRolePermissionService;
    @Autowired
    private JwtProperties jwtProperties;
    //    @Autowired
//    private LoginRedisService loginRedisService;
    @Autowired
    private ShiroProperties shiroProperties;


    @Override
    public ApiResult login(LoginParam loginParam, HttpServletResponse response) {
        LoginSysUserTokenVo loginSysUserTokenVo = null;
        Map<String, Object> retMap = new HashMap<>();
        try {
            //1.校验验证码
            checkVerifyCode(loginParam.getVerifyToken(), loginParam.getCode());
            //2.
            Map<String, Object> loginMap = new HashMap<>();
            String username = loginParam.getUsername();
            loginMap.put("username", username);
            loginMap.put("password", loginParam.getPassword());
            SysUser sysUser = sysUserService.getSysUserByPwd(loginMap);

            if (sysUser == null) {
                logger.info("登录失败，loginParam:{}", loginParam);
                return ApiResult.fail("用户名或密码错误");
            }
            if ("0".equals(sysUser.getState())) {
                return ApiResult.fail("账号已禁用！");
            }
            LoginSysUserVo loginSysUserVo = new LoginSysUserVo();

            loginSysUserVo.setId(sysUser.getId());
            loginSysUserVo.setUsername(sysUser.getUsername());
            loginSysUserVo.setNickname(sysUser.getNickname());
            loginSysUserVo.setGender(sysUser.getGender());
            loginSysUserVo.setState(sysUser.getState());


            //获取部门信息
            SysDepartment department = departmentService.getDepartmentById(sysUser.getDepartmentId() + "");
            if (department == null) {

                return ApiResult.fail("部门不存在");

            }
            if ("1".equals(department.getState())) {
                return ApiResult.fail("部门已禁用");
            }
            loginSysUserVo.setDepartmentId(department.getId());
            loginSysUserVo.setDepartmentName(department.getDeptName());
            //获取当前用户角色
            Long roleId = sysUser.getRoleId();
            SysRole sysRole = sysRoleService.getSysRoleById(roleId);
            if (sysRole == null) {
                return ApiResult.fail("角色不存在");
            }
            if ("0".equals(sysRole.getState())) {
                return ApiResult.fail("角色已禁用");
            }
            loginSysUserVo.setRoleId(sysRole.getId());
            loginSysUserVo.setRoleName(sysRole.getRoleName());
            loginSysUserVo.setRoleCode(sysRole.getCode());

            //获取当前用户的权限
            Set<String> permissionCodes = sysRolePermissionService.getPermissionCodesByRoleId(roleId + "");

            if (CollectionUtils.isEmpty(permissionCodes)) {
                return ApiResult.fail("权限列表不能为空");
            }

            loginSysUserVo.setPermissionCodes(permissionCodes);
            String newSalt = SaltUtil.getSalt(sysUser.getSalt(), jwtProperties);
            Long expireSecond = jwtProperties.getExpireSecond();
            String token = JwtUtil.generateToken(username, newSalt, Duration.ofSeconds(expireSecond));
            logger.info("token:{}", token);

            //创建AuthenticationToken
            JwtToken jwtToken = JwtToken.build(token, username, newSalt, expireSecond);
            boolean enableShiro = false;
            if (enableShiro) {
                Subject subject = SecurityUtils.getSubject();
                subject.login(jwtToken);
            } else {
                logger.info("未启用 Shiro！");
            }

            // 缓存登录信息到Redis
//            loginRedisService.cacheLoginInfo(jwtToken, loginSysUserVo);
            logger.debug("登录成功,username:{}", username);

            //缓存登录信息到redis
//            String tokenSha256 = DigestUtils.sha256Hex(token);
//            redisTemplate.opsForValue().set(tokenSha256, loginSysUserVo, 1, TimeUnit.DAYS);

            //返回token和登录用户信息对象
            loginSysUserTokenVo = new LoginSysUserTokenVo();
            loginSysUserTokenVo.setToken(token);
            loginSysUserTokenVo.setLoginSysUserVo(loginSysUserVo);

            retMap.put("token", token);
            retMap.put("userInfo", JSONObject.toJSON(loginSysUserVo));


            // 设置token响应头
            response.setHeader(JwtTokenUtil.getTokenName(), loginSysUserTokenVo.getToken());
        } catch (Exception e) {
            logger.error(">>>>>>>>>>>>>>>>>>登录失败：", e);
            ApiResult.fail("登录失败：" + e);

        }
        logger.info(">>>>>>>>>>>>>>>>>>>>>返回：：：：" + loginSysUserTokenVo.toString());
        return ApiResult.ok(retMap, "登录成功");

    }

    @Override
    public void logout(HttpServletRequest request) throws Exception {
        boolean enableShiro = shiroProperties.isEnable();
        if (enableShiro) {
            Subject subject = SecurityUtils.getSubject();
            //注销
            subject.logout();
        }
        String token = JwtTokenUtil.getToken(request);

        //获取token
//        String token = param.getToken();
        String userName = JwtUtil.getUsername(token);
        //删除redis缓存
//        loginRedisService.deleteLoginInfo(token, userName);
    }

    @Override
    public SysUser getSysUserByUserName(String userName) throws Exception {
        return null;
    }

    @Override
    public SysUser getSysUserByPassWord(Map<String, Object> paramsMap) throws Exception {
        return null;
    }

    @Override
    public void checkVerifyCode(String verifyToken, String code) throws Exception {

        //是否启用验证码 这个地方配置
        boolean checkCode = false;
        if (!checkCode) {
            return;
        }
        //校验验证码
        if (StringUtils.isEmpty(code)) {
            throw new Exception("验证码不能为空");
        }
        String redisKey = String.format(CommonRedisKey.VERIFY_CODE, verifyToken);
//        String generateCode = (String) redisTemplate.opsForValue().get(redisKey);

//        if (StringUtils.isBlank(generateCode)) {
//            throw new Exception("验证码已过期或不正确！");
//        }
//        if (!generateCode.equalsIgnoreCase(code)) {
//            throw new Exception("验证码错误");
//        }
        //验证成功，则删除Redis缓存
//        redisTemplate.delete(redisKey);

    }

    @Override
    public void generateVerifyCode() throws Exception {
//        RandomValidateCodeUtil randomValidateCode = new RandomValidateCodeUtil();
//        randomValidateCode.getRandCode(request, response);//输出验证码图片方法

    }

    @Override
    public ApiResult verifyAuthToken(String token) {
        Map<String, Object> resultMap = new HashMap<>();
//        boolean exists = loginRedisService.exists(token);
//        if (exists) {
//            LoginSysUserVo loginSysUserVo = loginRedisService.getLoginSysUserRedisVoByToken(token);
//            resultMap.put("rows", JSONObject.toJSON(loginSysUserVo));
//            resultMap.put("token", token);
//        } else {
//            return ApiResult.fail("Token已过期");
//        }

        return ApiResult.ok(resultMap);
    }

    @Override
    public ApiResult resetPassword(ResetPwdParam resetPwdParam) {

        String username = resetPwdParam.getUsername();

        if (StringUtils.isEmpty(username)) {
            return ApiResult.fail("用户名不能为空");
        }
        if (StringUtils.isEmpty(resetPwdParam.getOldPwd())) {
            return ApiResult.fail("旧密码不能为空!");
        }
        if (StringUtils.isEmpty(resetPwdParam.getNewPwd())) {
            return ApiResult.fail("新密码不能为空！");
        }

        try {
            Map<String, Object> loginMap = new HashMap<>();
            loginMap.put("username", username);
            loginMap.put("password", resetPwdParam.getOldPwd());
            SysUser sysUser = sysUserService.getSysUserByPwd(loginMap);
            if (sysUser == null) {
                return ApiResult.fail("账号或密码不正确!");
            }
            Map<String, Object> resetMap = new HashMap<>();
            resetMap.put("id", sysUser.getId());
            String newPwd = DigestUtils.md5Hex(resetPwdParam.getNewPwd());
            resetMap.put("password", newPwd);
            boolean b = sysUserService.resetPassword(resetMap);

        } catch (Exception e) {
            logger.error(">>>>>>>>>>>>>>>>>>>>>>>>>密码重置失败", e);
            e.printStackTrace();
            return ApiResult.fail("密码重置失败" + e.getMessage());
        }


        return ApiResult.ok("密码重置成功!");
    }
}
